package com.exercise.storage.api;

import com.exercise.commons.param.QueryOrderParam;
import com.exercise.commons.po.OrderDO;
import com.exercise.commons.utils.UUIDUtils;
import com.exercise.commons.vo.*;
import com.exercise.storage.apiParam.OrderParam;
import com.exercise.storage.mapper.OrderMapper;
import com.exercise.storage.service.OrderService;
import com.exercise.storage.service.ProductDetailService;
import com.exercise.storage.service.ProductService;
import com.exercise.storage.service.UserService;
import com.exercise.storage.service.impl.OrderServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController
@RequestMapping ("/order")
public class OrderServiceApi {

        private static final Logger logger = LoggerFactory.getLogger(com.exercise.storage.service.impl.OrderServiceImpl.class);
        @Autowired
        private RedissonClient redisson;
        @Autowired
        private OrderMapper orderMapper;
        @Autowired
        private ProductDetailService productDetailService;
        @Autowired
        private UserService userService;
        @Autowired
        private ProductService productService;

        @RequestMapping ("/add")
        public Order add(Order order) {

            if (order == null) {
                return null;
            }
            //根据商品Id查询商品信息
            ProductDetail productDetail = productDetailService.get(order.getProductDetailId());
            if (productDetail == null) {
                return null;
            }
            order.setTotalPrice(productDetail.getPrice());
            order.setId(UUIDUtils.getUUID());
            order.setStatus(OrderStatus.WAIT_BUYER_PAY);
            //生成唯一订单号
            order.setOrderNumber(createOrderNumber());
            OrderDO orderDO = new OrderDO(order);
            int insert = orderMapper.insert(orderDO);
            if (insert == 1) {
                return order;
            }
            return null;
        }

        @RequestMapping ("/getByOrderNumber")
        public Order getByOrderNumber(String orderNumber) {
            if (StringUtils.isEmpty(orderNumber)) {
                return null;
            }
            OrderDO orderDO = orderMapper.selectByOrderNumber(orderNumber);
            if (orderDO != null) {
                Order order = orderDO.convertToModel();
                return order;
            }
            return null;
        }

        @RequestMapping ("/updateOrderStatus")
        public Order updateOrderStatus(OrderParam orderParam) {
            //更改订单状态
            OrderDO orderDO = orderMapper.selectByOrderNumber(orderParam.getOrderNumber());
            if (orderDO == null) {
                return null;
            }
            orderDO.setStatus(orderParam.getOrderStatus().toString());
            orderMapper.update(orderDO);
            return orderDO.convertToModel();
        }

        @RequestMapping ("/updateProductPersonNumber")
        public Order updateProductPersonNumber(String orderNumber) {
            OrderDO orderDO = orderMapper.selectByOrderNumber(orderNumber);
            if (orderDO == null) {
                return null;
            }
            //获取分布式锁
            RLock transferLock = redisson.getLock("PURCHASE");
            transferLock.lock();
            try {
                ProductDetail productDetail = productDetailService.get(orderDO.getProductDetailId());
                if (productDetail == null) {
                    return null;
                }
                productDetail.setStock(productDetail.getStock() - 1);
                productDetailService.save(productDetail);
                Product product = productService.get(productDetail.getProductId());
                product.setPurchaseNum(product.getPurchaseNum() + 1);
                productService.save(product);
            } catch (Exception e) {
                logger.error("", e);
            } finally {
                transferLock.unlock();
            }
            return orderDO.convertToModel();
        }

        @RequestMapping ("/queryRecentPaySuccess")
        public Paging<Order> queryRecentPaySuccess(QueryOrderParam queryOrderParam) {
            Paging<Order> result = new Paging<>();

            if (queryOrderParam == null) {
                queryOrderParam = new QueryOrderParam();
            }

            int counts = orderMapper.selectCounts(queryOrderParam);

            if (counts < 1) {
                result.setTotalCount(0);
                return result;
            }
            List<OrderDO> orderDOS = orderMapper.pageQuery(queryOrderParam);
            List<Order> orders = new ArrayList<>();
            List<String> productDetailIds = new ArrayList<>();
            List<Long> userIds = new ArrayList<>();
            for (OrderDO orderDO : orderDOS) {
                orders.add(orderDO.convertToModel());
                productDetailIds.add(orderDO.getProductDetailId());
                userIds.add(Long.parseLong(orderDO.getUserId()));
            }
            List<User> users = userService.queryUser(userIds);
            List<ProductDetail> productDetails = productDetailService.queryProductDetail(productDetailIds);
            Map<String, ProductDetail> productDetailMap = productDetails.stream().collect(
                    Collectors.toMap(ProductDetail::getId, t -> t));
            Map<Long, User> userMap = users.stream().collect(Collectors.toMap(User::getId, t -> t));

            for (Order order : orders) {
                order.setProductDetail(productDetailMap.get(order.getProductDetailId()));
                order.setUser(userMap.get(order.getUserId()));
            }
            result.setData(orders);
            result.setTotalCount(counts);
            result.setPageNum(orders.size());
            result.setPageSize(queryOrderParam.getPageSize());
            result.setTotalPage(orders.size() / queryOrderParam.getPageNum());
            return result;
        }

        /**
         * 生成唯一订单号
         *
         * @return String
         */
        private String createOrderNumber() {
            LocalDateTime localDateTime = LocalDateTime.now();
            DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
            String date = dtf2.format(localDateTime);
            RAtomicLong aLong = redisson.getAtomicLong("myOrderPartNum" + date);
            aLong.expire(10, TimeUnit.SECONDS);
            long count = aLong.incrementAndGet();
            String orderId = date + count;
            return orderId;
        }

}
